/* 
 *  Copyright 2012 CodeMagi, Inc.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.codemagi.servlets.content.model;

import com.codemagi.login.model.IUser;
import com.codemagi.servlets.model.Node;
import com.codemagi.util.OrderedTable;
import java.io.Serializable;
import java.util.*;

/**
 * Models a page on a website.
 *
 * @version 1.0
 * @author August Detlefsen for CodeMagi, Inc.
 */
public class NavPage extends com.codemagi.servlets.model.Node implements Serializable {

    //members                                                                          
    private String keywords;
    private String link;
    private ISection section;
    private Integer sortOrder;
    private Boolean loginRequired = new Boolean(false);
    private Boolean display       = new Boolean(true);
    private Boolean displayHome   = new Boolean(true);
    private Date expireDate       = null;
    //    private Date dateCreated      = new Date();
    private Integer templateId;


    //GETTERS AND SETTERS ------------------------------------                                                                  

    public void setKeywords(String newValue) {
        keywords = newValue;
    }

    public String getKeywords() {
        return keywords;
    }

    public void setLink(String newValue) {
        link = newValue;
    }

    public String getLink() {
        return link;
    }

    public void setSection(ISection newValue) {
        section = newValue;
    }

    public ISection getSection() {
        return section;
    }

    public void setSortOrder(Integer newValue) {
        sortOrder = newValue;
    }

    public Integer getSortOrder() {
        return sortOrder;
    }

    public void setLoginRequired(Boolean newValue) {
        if (newValue != null) loginRequired = newValue;
    }

    public Boolean getLoginRequired() {
        return loginRequired;
    }


    public void setDisplay(Boolean newValue) {
        if (newValue != null) display = newValue;
    }

    public Boolean getDisplay() {
        return display;
    }


    public void setDisplayHome(Boolean newValue) {
        if (newValue != null) displayHome = newValue;
    }

    public Boolean getDisplayHome() {
        return displayHome;
    }


    public void setExpireDate(Date newValue) {
	expireDate = newValue;
    }

    public Date getExpireDate() {
        return expireDate;
    }


    /**
     * @deprecated   Replaced by Node.setCreatedDate()
     */
    public void setDateCreated(Date newValue) {
	setCreatedDate(newValue);
    }

    /**
     * @deprecated   Replaced by Node.getCreatedDate()
     */
    public Date getDateCreated() {
        return getCreatedDate();
    }


    public void setTemplateId(Integer newValue) {
	templateId = newValue;
    }

    public Integer getTemplateId() {
        return templateId;
    }


    //SPECIAL GETTERS AND SETTERS ------------------------------                                                            

    public Integer getSectionId() {
	return section == null ? new Integer(0) : section.getId();
    }

    public String getSectionName() {
	if (section == null) return "";

	return section.getName();
    }

    public boolean hasChildren() {
        return (!getChildren(com.codemagi.servlets.content.model.NavPage.class).isEmpty());
    }

    /**
     * Returns true if this nav page has at least one visible child
     */
    public boolean hasVisibleChildren() {
        if ( children.isEmpty() ) return false;

	Iterator i     = getChildren(com.codemagi.servlets.content.model.NavPage.class).iterator();
	while (i.hasNext()) {
	    NavPage child = (NavPage)i.next();

	    if (child.display()) return true;
	}

	return false;
    }

    /**
     * Returns true if this nav page has at least one visible 
     * child that the passed user is allowed to view
     */
    public boolean hasVisibleChildren(IUser user) {
        if ( children.isEmpty() ) return false;

	Iterator i     = getChildren(com.codemagi.servlets.content.model.NavPage.class).iterator();
	while (i.hasNext()) {
	    NavPage child = (NavPage)i.next();

	    if (!user.isAuthenticated() && child.isLoginRequired()) continue;

	    if (child.display()) return true;
	}

	return false;
    }

    public List<NavPage> getSiblings() {
	Node parent = getParent();

        if (parent == null || !(parent instanceof NavPage)) return new ArrayList();

        return parent.getChildren(com.codemagi.servlets.content.model.NavPage.class);
    }

    public boolean isRootPage() {
	return (getParent() == null);
    }

    public boolean isLoginRequired() {
        return loginRequired.booleanValue();
    }

    public boolean display() {
        return display.booleanValue();
    }

    public boolean displayHome() {
        return displayHome.booleanValue();
    }

    public String getPageTitle() {
        return getName();
    }

    public String getParentPageTitle() {
	Node parent = getParent();

        if (parent == null || !(parent instanceof NavPage)) return "";

        return parent.getName();
    }

    public Integer getParentPageId() {
	Node parent = getParent();

        if (parent == null) return null;

        return parent.getId();
    }

    public OrderedTable getBreadcrumbs() {
        return getBreadcrumbs(this, new OrderedTable());
    }


    private OrderedTable getBreadcrumbs(NavPage page, OrderedTable breadcrumbs) {

        if (page == null || page.getId() == null) return breadcrumbs;

        breadcrumbs.putAt(page.getLink(), page.getName(), 0);

        Node parentPage = page.getParent();
        if (parentPage != null && parentPage.getId() != null && parentPage instanceof NavPage) {
            return getBreadcrumbs( (NavPage)parentPage, breadcrumbs);
        }

        return breadcrumbs;
    }

    /**
     * Returns this NavPage's level in the page hierarchy
     */
    public int getLevel() {
	if ( isRootPage() ) return 0;

	int level = 1;
	Node testParent = getParent();
	while ( testParent != null && testParent instanceof NavPage && !((NavPage)testParent).isRootPage() ) {
	    level++;
	    testParent = testParent.getParent();
	}

	return level;
    }

    /**
     * Returns true if this NavPage has the passed NavPage as an ancestor
     */
    public boolean hasAncestor(NavPage input) {

	//sanity check
	if (input == null) return false;

        Node testParent = getParent();
        while ( testParent != null ) {
	    if (testParent.getId().equals(input.getId()) ) return true;
	    
            testParent = testParent.getParent();
        }

	return false;
    }


    /**
     * Returns true if this NavPage has the NavPage represented by the passed ID as an ancestor
     */
    public boolean hasAncestor(Integer input) {
        Node testParent = getParent();
        while ( testParent != null ) {
	    if (testParent.getId() != null && testParent.getId().equals(input) ) return true;
	    
            testParent = testParent.getParent();
        }

	return false;
    }


    public boolean hasUser(IUser user) {
	if (section == null) return false;

	return user.isSuperuser() || section.hasUser(user);
    }


    public boolean isExpired() {
	return (expireDate != null && expireDate.before(new Date()) );
    }


    //UTILITY METHODS ---------------------------------------------                                              


    class Sorter implements Comparator {
        public int compare(Object o1, Object o2) {

	    int output = 0;

            try {
		NavPage n1 = (NavPage)o1;
		NavPage n2 = (NavPage)o2;

		if ( n1.getSortOrder() != null && n2.getSortOrder() != null ) {
		    output = n1.getSortOrder().compareTo( n2.getSortOrder() );

		} else if ( n2.getSortOrder() == null && n1.getSortOrder() != null ) {
		    output = -1;

		} else if ( n1.getSortOrder() == null && n2.getSortOrder() != null ) {
		    output =  1;

		} else {
		    output = n1.getName().compareTo( n2.getName() );

		}

            } catch (Exception e) {
                //NullPointerException, ClassCastException, for example                             
            }

            return output;
        }
    }
}
